//-----------------------------------------------------------------------------
//  File          : SecuFile.c
//  Module        :
//  Description   : Handle SecuFile command.
//  Author        : Lewis
//  Notes         :
//
// ============================================================================
// | Naming conventions                                                       |
// | ~~~~~~~~~~~~~~~~~~                                                       |
// |        Struct define : Leading T                                         |
// |         Struct/Array : Leading s                                         |
// |             Constant : Leading K                                         |
// |      Global Variable : Leading g  (variable use outside one C file)      |
// |                                                                          |
// |   BYTE( 8 Bits) size : Leading b                                         |
// |   CHAR( 8 Bits) size : Leading c                                         |
// |   WORD(16 Bits) size : Leading w                                         |
// |  DWORD(32 Bits) size : Leading d                                         |
// |    int(32 Bits) size : Leading i                                         |
// | DDWORD(64 Bits) size : Leading dd                                        |
// |              Pointer : Leading p                                         |
// |                                                                          |
// |    Function argument : Leading a                                         |
// |       Local Variable : All lower case                                    |
// |                                                                          |
// | Examples:                                                                |
// |                Array : Leading s, (sb = arrary of byte, etc)             |
// |              Pointer : Leading p, (pb = pointer of byte, etc)            |
// ============================================================================
//
//  Date          Who         Action
//  ------------  ----------- -------------------------------------------------
//  29 Sept 2008  Lewis       Initial Version (with new CD nameing convention)
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include "system.h"
#include "util.h"
#include "kbdutil.h"
#include "sysutil.h"
#include "SecuFile.h"

//----------------------------------------------------------------------------
//      Defines
//----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//      Globals
//-----------------------------------------------------------------------------
static int i_FileHandle = -1;
struct SECUR_DATA gSecurData, *gFileOffset;

//-----------------------------------------------------------------------------
//      Constant
//-----------------------------------------------------------------------------
static const char KSFileName[] = { "KDLLSecu" };

static const BYTE KSpectra[8] = "Spectra ";
static const BYTE KEprom[30]  = {0x7C,0x4E,0xF4,0x1F,0xEA,0xFF,0x39,0x54,
                                 0x7C,0x4E,0xF4,0x1F,0xEA,0xFF,0x39,0x54,
                                 0x31,0x32,0x33,0x34,0x35,0x36,0x36,0x35,
                                 0x34,0x33,0x32,0x31,0x0A,0x1E
                                };

//*****************************************************************************
//  Function        : DukptKeyReset
//  Description     : Reset all dukpt key bank or one.
//  Input           : aKeyIdx;        // index of key bank, 0 or 0xFF => All.
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
BOOLEAN DukptKeyReset(BYTE aKeyIdx)
{
  int i, start_idx, end_idx;
  BYTE tkey[16];

  if ((aKeyIdx != 0xFF) && (aKeyIdx >= MAX_DUKPTKEY_SUPPORT))
    return FALSE;

  if ((aKeyIdx == 0) || (aKeyIdx == 0xFF)) {
    start_idx = 0;
    end_idx   = MAX_KEYBANK_SUPPORT;
  }
  else {
    start_idx = aKeyIdx;
    end_idx   = start_idx + 1;
  }

  for (i = start_idx; i < end_idx; i++) {
    os_rand(tkey);
    os_rand(&tkey[8]);
    os_key_dukpt_key_inject(&gSecurData.s_dukpt[i], tkey);
  }
  return TRUE;
}
//*****************************************************************************
//  Function        : ResetKeyBank
//  Description     : Reset all key bank or one.
//  Input           : aKeyIdx;        // index of key bank, 0 or 0xFF => All.
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
void ResetKeyBank(int aKeyIdx)
{
  int i, start_idx, end_idx;
  BYTE tmp[32];

  if ((aKeyIdx != 0xFF) && (aKeyIdx >= MAX_KEYBANK_SUPPORT))
    return;

  if ((aKeyIdx == 0) || (aKeyIdx == 0xFF)) {
    start_idx = 0;
    end_idx   = MAX_KEYBANK_SUPPORT;
  }
  else {
    start_idx = aKeyIdx;
    end_idx   = start_idx + 1;
  }

  // Reset Key
  for (i = start_idx; i < end_idx; i++) {
    os_rand(tmp);
    os_rand(&tmp[8]);
    os_rand(&tmp[16]);
    os_key_save(tmp, gSecurData.s_keybank[i].sb_lkey, 2); // triple key len
    gSecurData.s_keybank[i].b_status = 0x00;
  }

  //Generate the Master Key for Reset All
  if ((aKeyIdx == 0) || (aKeyIdx == 0xFF)) {
    os_deskey(KSpectra);
    memset(tmp, 0x00, sizeof(tmp));
    memcpy(tmp, KEprom, 16);
    os_des2(tmp);
    os_des2(&tmp[8]);
    memcpy(&tmp[16], tmp, 8);
    os_key_save(tmp, gSecurData.s_keybank[0].sb_lkey, 2);  // use HSM
    gSecurData.s_keybank[0].b_status = KEY_STATUS_LOADED|KEY_STATUS_MASTER|KEY_STATUS_TRIPLE;
  }
  UpdateSecurData();
}
//*****************************************************************************
//  Function        : KeyStatus
//  Description     : Get key status;
//  Input           : aStatusStr;   // pointer to Key Status bytes
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
void KeyStatus(BYTE *aStatusStr)
{
  BYTE i;

  CheckPointerAddr(aStatusStr);
  for (i=0;i<MAX_KEYBANK_SUPPORT;i++)
  {
    aStatusStr[i] = gSecurData.s_keybank[i].b_status;
  }
}
//*****************************************************************************
//  Function        : CreateSecurData
//  Description     : Create Secure Data file with default value.
//  Input           : N/A
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
static void CreateSecurData(void)
{
  char filename[32], tmpbuf[SU_MAX_LINESIZE+1];

  strcpy(filename, KSFileName);
  i_FileHandle = os_file_create(filename, K_FILE_USR_READ|K_FILE_USR_WRITE|K_FILE_ACTIVE);
  if (i_FileHandle == -1) {
    DispLine(tmpbuf, SU_MAX_LINE, SU_REVERSE|SU_CLREOL|SU_SPFONT);
    while (os_kbd_getkey()==0) os_sleep();
    return;
  }
  memset(gSecurData.s_keybank, 0x00, sizeof(gSecurData.s_keybank));
  ResetKeyBank(0xFF);
  DukptKeyReset(0xFF);
  CommitFileIO();
  memset(&gSecurData, 0xFF, sizeof(gSecurData));
  os_file_seek(i_FileHandle, gFileOffset);
  os_file_read(i_FileHandle, &gSecurData, sizeof(struct SECUR_DATA));
}
//*****************************************************************************
//  Function        : SecuFileInit
//  Description     : Initial Secure File Variables.
//  Input           : N/A
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
void SecuFileInit(void)
{
  char filename[32];
  WORD crc_val;

  gFileOffset = 0;
  strcpy(filename, KSFileName);

  i_FileHandle = os_file_open(filename, K_O_RDWR);
  if (i_FileHandle >= 0) {	
    memset(&gSecurData, 0x00, sizeof(gSecurData));
    os_file_seek(i_FileHandle, gFileOffset);
    os_file_read(i_FileHandle, &gSecurData, sizeof(struct SECUR_DATA));
    crc_val = cal_crc((BYTE *)&gSecurData, (BYTE *)&gSecurData.w_crc_val - (BYTE *)&gSecurData);
    if (crc_val == gSecurData.w_crc_val)
      return ;	
    os_file_close(i_FileHandle);
    os_file_delete(filename);
    CommitFileIO();
  }
  CreateSecurData();
}
//*****************************************************************************
//  Function        : UpdateSecurData
//  Description     : Update Secure data to file.
//  Input           : N/A
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
void UpdateSecurData(void)
{  
  gSecurData.w_crc_val = cal_crc((BYTE *)&gSecurData, (BYTE *)&gSecurData.w_crc_val - (BYTE *)&gSecurData);
  os_file_seek(i_FileHandle, gFileOffset);
  os_file_write(i_FileHandle, &gSecurData, sizeof(struct SECUR_DATA));
  os_file_flushed(i_FileHandle);
  CommitFileIO();
}

